//
//  RZIMClient.m
//  RZIM
//
//  Created by reyzhang on 2021/7/26.
//

#import "RZIMClient.h"
#import "RZSocketRocketManager.h"
#import "RZErrorInfo.h"
#import <MJExtension/MJExtension.h>
#import "NSDictionary+Helper.h"
#import "RZApiManager.h"

@interface RZIMClient ()
@property (nonatomic, strong) RZSocketRocketManager *socketManager;

@property (nonatomic, copy) dispatch_block_t ConnectSuccessBlock;
@property (nonatomic, copy) void(^ConnectErrorBlock)(RZIMConnectErrorCode errorCode);
@property (nonatomic, strong) NSString  *token;
@end

@implementation RZIMClient

static RZIMClient *_instance;
static dispatch_once_t onceToken;
+ (instancetype)sharedClient {
    dispatch_once(&onceToken, ^{
        _instance = [[RZIMClient alloc] init];
    });
    return _instance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self commonInit];
    }
    return self;
}

 
+(void)attempDealloc {
    onceToken = 0; // 只有置成0,GCD才会认为它从未执行过.它默认为0.这样才能保证下次再次调用shareInstance的时候,再次创建对象.
    _instance = nil;
}


- (void)dealloc {
    NSLog(@"RZIM dealloc");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)commonInit {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(websocketDidOpen:) name:RZNotification_SocketRocketDidOpen object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(websocketDidOpenFailure:) name:RZNotification_SocketRocketDidOpenFailure object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(websocketDidClose:) name:RZNotification_SocketRocketDidClose object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(websocketDidReceive:) name:RZNotification_SocketRocketDidReceive object:nil];
    
    //进入前台 or 后台 模式的监听
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(runningModeChanged:) name:UIApplicationWillEnterForegroundNotification object:@(RZSDKRunningMode_Foreground)];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(runningModeChanged:) name:UIApplicationDidEnterBackgroundNotification object:@(RZSDKRunningMode_Background)];
    _sdkRunningMode = RZSDKRunningMode_Foreground;
}




#pragma mark WebSocket Notification Handler
- (void)websocketDidOpen:(NSNotification *)notif {
    //连接成功后，存储token
    [[NSUserDefaults standardUserDefaults] setObject:self.token forKey:kAuthTokenKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    self.connectStatus = ConnectionStatus_Connected;
    //连接成功的回调处理 delegate & block
    if ([self.connectionStatusDelegate respondsToSelector:@selector(onRZIMConnectionStatusChanged:)]) {
        [self.connectionStatusDelegate onRZIMConnectionStatusChanged:ConnectionStatus_Connected];
    }
    !self.ConnectSuccessBlock ?: self.ConnectSuccessBlock();
}

- (void)websocketDidOpenFailure:(NSNotification *)notif {
    
    NSError *error =  notif.object;
    RZConnectionStatus status = ConnectionStatus_Unconnected; //连接失败或未连接
    if (error) {
        RZIMConnectErrorCode code = RZ_CONN_UNKNOW;
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        
        switch (userInfo.errorCode) {
            case 401:
                code = RZ_CONN_TOKEN_INCORRECT;
                status = ConnectionStatus_TOKEN_INCORRECT;
                
                break;
                
            default:
                break;
        }
        
        
        //回调处理 delegate & block
        self.connectStatus = status;
        if ([self.connectionStatusDelegate respondsToSelector:@selector(onRZIMConnectionStatusChanged:)]) {
            [self.connectionStatusDelegate onRZIMConnectionStatusChanged:status];
        }
        
        !self.ConnectErrorBlock ?: self.ConnectErrorBlock(code);
    }
    
}

- (void)websocketDidClose:(NSNotification *)notif {
    
    self.connectStatus = ConnectionStatus_DISCONN_EXCEPTION;
    //回调处理 delegate & block
    if ([self.connectionStatusDelegate respondsToSelector:@selector(onRZIMConnectionStatusChanged:)]) {
        [self.connectionStatusDelegate onRZIMConnectionStatusChanged:ConnectionStatus_DISCONN_EXCEPTION];
    }
    
}


- (void)websocketDidReceive:(NSNotification *)notif {
    RZMessage *msgInfo = (RZMessage *)notif.object;
    if ([msgInfo isKindOfClass:[RZMessage class]]) {
        if (msgInfo.message.msgType == MessageType_SYS_OTHERLOGIN) {
            //回调处理 delegate & block
            if ([self.connectionStatusDelegate respondsToSelector:@selector(onRZIMConnectionStatusChanged:)]) {
                [self.connectionStatusDelegate onRZIMConnectionStatusChanged:ConnectionStatus_KICKED_OFFLINE_BY_OTHER_CLIENT];
            }
        }else if (msgInfo.message.msgType == MessageType_SYS_SERVERDISCONNECT) {
            //回调处理 delegate & block
            if ([self.connectionStatusDelegate respondsToSelector:@selector(onRZIMConnectionStatusChanged:)]) {
                [self.connectionStatusDelegate onRZIMConnectionStatusChanged:ConnectionStatus_DISCONN_EXCEPTION];
            }
        }
    }
}


- (void)runningModeChanged:(NSNotification *)notif {
    _sdkRunningMode = [notif.object integerValue];
}


#pragma mark Public Method
/**
 根据Token连接 websocket
 @token 拿到用户登录后的token，用来鉴权
 */
- (void)connectWithToken:(NSString *)token
                 success:(dispatch_block_t)successBlock
                   error:(void (^)(RZIMConnectErrorCode errorCode))errorBlock {
    
    self.token = token;
    self.ConnectSuccessBlock = successBlock;
    self.ConnectErrorBlock =  errorBlock;
    
    if (!token.length || token.length == 0) {
        errorBlock(RZ_CONN_TOKEN_INCORRECT);
        return;
    }
    
    //检查初始化配置
    if (![RZIMConfig sharedConfig].socketURL.length ||
        [RZIMConfig sharedConfig].socketURL.length == 0) {
        errorBlock(RZ_CLIENT_NOT_INIT_Config); //没有初始化配置
        return;
    }
    
    
    self.socketManager = [RZSocketRocketManager shareInstance];
    [self.socketManager openWithURLString:[RZIMConfig sharedConfig].socketURL token:token];
    
    //TODO:可以使用KVO来观察 socketManager的 socketReadyState属性的变化。如果使用不当会造成内存泄露，暂时通过它的代理来判断状态
}

/**
 关闭连接
 */
- (void)disconnect {
    //关闭socket
    [self.socketManager close];
}

/**
 关闭连接，并关闭重连机制。避免因为连接异常，进入无限的重连机制
 */
- (void)disReConnect {
    [self disconnect];
    self.socketManager.needReConnect = NO;
}




/**
 发送消息,调用RZApiManager接口的sendMessage方法
 */
- (void)sendMessageWithGroupId:(NSString *)groupId
                   content:(RZMessageContent *)content
                   success:(dispatch_block_t)successBlock
                     error:(ErrorBlock)errorBlock {
    
    [RZApiManager sendMessageWithGroupId:groupId
                                 message:content.msg
                             messageType:content.msgType
                               extraData:content.extraData
                                 success:^(NSDictionary * _Nonnull dic) {
        if([dic isSuccess]) {
            !successBlock ?: successBlock();
        }else {
            !errorBlock ?: errorBlock(SEND_MSG_ERROR,dic[kResponseMsgKey]);
        }
    } failure:^(NSError * _Nonnull error) {
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        !errorBlock ?: errorBlock(SEND_MSG_ERROR, userInfo.errorMessage);
    }];
}



/**
 刷新用户信息
 @userInfo 要更新的用户信息
 */
- (void)refreshUserInfo:(RZUserInfo *)userInfo {
    [RZApiManager updateUserInfoWithUserId:userInfo.uid name:userInfo.username avatar:userInfo.userAvatar success:^(NSDictionary * _Nonnull dic) {
        NSLog(@"更新用户信息成功");
    } failure:^(NSError * _Nonnull error) {
        NSLog(@"更新用户信息失败");
    }];
}


/**
 加入私聊，调用RZApiManager接口的createPrivateChat方法
 @label 标签，分组会话
 */
- (void)joinPrivateChatWithTargetId:(NSString *)tid
                              label:(NSInteger)label
                            success:(void(^)(RZGroupInfo *groupInfo))successBlock
                              error:(ErrorBlock)errorBlock {
    
    [RZApiManager createPrivateChatWithTargetId:tid
                                          label:label
                                        success:^(NSDictionary * _Nonnull dic) {
        if ([dic isSuccess]) {
            id data = dic[kResponseDataKey];
            RZGroupInfo *groupInfo = [RZGroupInfo mj_objectWithKeyValues:data[@"group"]];
            !successBlock ?: successBlock(groupInfo);
        }else{
            !errorBlock ?: errorBlock(JOIN_PRIVATE_CHAT_ERROR,dic[kResponseMsgKey]);
        }
    } failure:^(NSError * _Nonnull error) {
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        !errorBlock ?: errorBlock(JOIN_PRIVATE_CHAT_ERROR, userInfo.errorMessage);
    }];
}

/**
 加入私聊,不分组会话
 */
- (void)joinPrivateChatWithTargetId:(NSString *)tid
                            success:(void(^)(RZGroupInfo *groupInfo))successBlock
                              error:(ErrorBlock)errorBlock {
    [self joinPrivateChatWithTargetId:tid label:0 success:successBlock error:errorBlock];
}




/**
 创建群组
 @label标签，可以用来分组会话
 */
- (void)createGroupWithName:(NSString *)name
                   portrait:(NSString *)portrait
                       uids:(NSArray *)uidsList
                      label:(NSInteger)label
                    success:(void(^)(RZGroupInfo *groupInfo))successBlock
                      error:(ErrorBlock)errorBlock {
    
    NSString *uids = [uidsList componentsJoinedByString:@","]; //用,号分割
    [RZApiManager createGroupWithName:name portrait:portrait uids:uids label:label success:^(NSDictionary * _Nonnull dic) {
        if ([dic isSuccess]) {
            id data = dic[kResponseDataKey];
            RZGroupInfo *groupInfo = [RZGroupInfo mj_objectWithKeyValues:data[@"group"]];
            !successBlock ?: successBlock(groupInfo);
        }else{
            !errorBlock ?: errorBlock(CREATE_GROUP_ERROR,dic[kResponseMsgKey]);
        }
    } failure:^(NSError * _Nonnull error) {
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        !errorBlock ?: errorBlock(CREATE_GROUP_ERROR, userInfo.errorMessage);
    }];
}


/**
 创建群组， 不分组会话
 */
- (void)createGroupWithName:(NSString *)name
                   portrait:(NSString *)portrait
                       uids:(NSArray *)uidsList
                    success:(void(^)(RZGroupInfo *groupInfo))successBlock
                      error:(ErrorBlock)errorBlock {
    [self createGroupWithName:name portrait:portrait uids:uidsList label:0 success:successBlock error:errorBlock];
    
}


/**
 获取会话列表
 @conversationTypeList 会话类型的数组，需要将 RZConversationType 转为 NSNumber 构建 Array
 @label 标签， 分组会话
 */
- (void)getConversationList:(NSArray<NSNumber*> *)conversationTypeList
                      count:(NSInteger)count
                      label:(NSInteger)label
                    success:(void(^)(NSArray<RZConversation *> *dataSource))successBlock
                      error:(ErrorBlock)errorBlock {
    NSString *types = @"";
    for (NSNumber *obj in conversationTypeList) {
        types = [types stringByAppendingFormat:@"%ld,",(long)[obj integerValue]];
    }
    if (conversationTypeList.count > 0) {
        types = [types substringToIndex:types.length-1];
    }
    
    [RZApiManager groupListWithPage:1 pageSize:count == 0 ? 999 : count groupType:types label:label queryStr:@"" success:^(NSDictionary * _Nonnull dic) {
        if ([dic isSuccess]) {
            id data = dic[kResponseDataKey];
            NSArray *dataArray =[RZConversation mj_objectArrayWithKeyValuesArray:data[@"records"]];
            !successBlock ?: successBlock(dataArray);
        }else{
            !errorBlock ?: errorBlock(GET_CONVERSATION_ERROR,dic[kResponseMsgKey]);
        }
    } failure:^(NSError * _Nonnull error) {
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        !errorBlock ?: errorBlock(GET_CONVERSATION_ERROR, userInfo.errorMessage);
    }];
}


/**
 获取会话列表，不分组会话
 */
- (void)getConversationList:(NSArray<NSNumber*> *)conversationTypeList
                      count:(NSInteger)count
                    success:(void(^)(NSArray<RZConversation *> *dataSource))successBlock
                      error:(ErrorBlock)errorBlock {
    [self getConversationList:conversationTypeList count:count label:0 success:successBlock error:errorBlock];
}


/**
 删除会话
 */
- (void)removeConversationWithTargetId:(NSString *)groupId
                               success:(dispatch_block_t)successBlock
                                 error:(ErrorBlock)errorBlock {
    
    [RZApiManager removeConversationWithGroupId:groupId success:^(NSDictionary * _Nonnull dic) {
        if ([dic isSuccess]) {
            !successBlock ?: successBlock();
        }else{
            !errorBlock ?: errorBlock(REMOVE_CONVERSATION_ERROR,dic[kResponseMsgKey]);
        }
    } failure:^(NSError * _Nonnull error) {
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        !errorBlock ?: errorBlock(REMOVE_CONVERSATION_ERROR, userInfo.errorMessage);
    }];
    
}


/**
 获取会话详情
 */
- (void)getConversationWithTargetId:(NSString *)groupId
                            success:(void(^)(RZConversation *conversation))successBlock
                              error:(ErrorBlock)errorBlock {
    [RZApiManager getGroupDetailWithGroupId:groupId success:^(NSDictionary * _Nonnull dic) {
        if ([dic isSuccess]) {
            id data = dic[kResponseDataKey];
            RZConversation *conversation = [RZConversation mj_objectWithKeyValues:data];
            !successBlock ?: successBlock(conversation);
        }else {
            !errorBlock ?: errorBlock(GET_CONVERSATION_DETAIL_ERROR, dic[kResponseMsgKey]);
        }
    } failure:^(NSError * _Nonnull error) {
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        !errorBlock ?: errorBlock(GET_CONVERSATION_DETAIL_ERROR, userInfo.errorMessage);
    }];
}



#pragma mark - 消息相关

- (void)getHistoryMessageWithTargetId:(NSString *)groupId
                                 page:(NSInteger)pageIndex
                             pageSize:(NSInteger)pageSize
                              success:(void(^)(NSArray<RZMessageInfo *> *dataSource, NSInteger totalPage))successBlock
                                error:(ErrorBlock)errorBlock {
    [RZApiManager messageListWithGroupId:groupId page:pageIndex pageSize:pageSize queryStr:@"" success:^(NSDictionary * _Nonnull dic) {
        if ([dic isSuccess]) {
            id data = dic[kResponseDataKey];
            NSInteger totalPage =  [data[@"pages"] integerValue];
            NSArray *dataArray =[RZMessageInfo mj_objectArrayWithKeyValuesArray:data[@"records"]];
            !successBlock ?: successBlock(dataArray,totalPage);
        }else{
            !errorBlock ?: errorBlock(GET_MESSAGE_ERROR,dic[kResponseMsgKey]);
        }
    } failure:^(NSError * _Nonnull error) {
        RZErrorInfo *userInfo = [RZErrorInfo mj_objectWithKeyValues:error.userInfo];
        !errorBlock ?: errorBlock(GET_MESSAGE_ERROR, userInfo.errorMessage);
    }];
}


/**
 上传多媒体消息
 */
- (void)sendMediaMessage:(RZMessage *)message
                progress:(void (^)(int progress, RZMessage *progressMessage))progressBlock
            successBlock:(void (^)(RZMessage *successMessage))successBlock
              errorBlock:(void (^)(RZErrorCode nErrorCode, RZMessage *errorMessage))errorBlock {
    
    
    
    
}


@end
